package tools.hmmer;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Hashtable;
import java.util.Vector;

public class hmmerUtils {
	static String sep="\t";

	/**
	 * @param args
	 */
	public static void main(String[] args)throws Exception {
		//args=new String[]{"antiSubTop","/local/membrane_protein/hmm/pfam_IN_GO_cellular_component.hmmer","/local/membrane_protein/GO_membrane_qname.txt"};
		if(args.length>0){
			if(args[0].equals("subTop")){
				if(args.length==3){
					extract_topDomains(args[1],args[2],true);
				}else{
					System.out.println(printHelp());
					System.exit(616);
				}
			}else if(args[0].equals("antiSubTop")){
				if(args.length==3){
					extract_topDomains(args[1],args[2],false);
				}else{
					System.out.println(printHelp());
					System.exit(616);
				}
			}else if(args[0].equals("cluster")){
				if(args.length==3){
					cluster(args[1],Integer.parseInt(args[2]));
				}else{
					System.out.println(printHelp());
					System.exit(616);
				}
			}else if(args[0].equals("tabulated")){
				if(args.length==2){
					tabulated(args[1]);
				}else{
					System.out.println(printHelp());
					System.exit(616);
				}
			}else if(args[0].equals("tabulatedTop")){
				if(args.length==3){
					tabulatedTop(args[1],Integer.parseInt(args[2]));
				}else{
					System.out.println(printHelp());
					System.exit(616);
				}
			}
		}else{
			System.out.println(printHelp());
			System.exit(616);
		}
	}

	private static String printHelp(){
		String help="Usage: hmmerUtils <cmd> <input>\n";
		help+="where <cmd> is:\n";
		help+="subTop - extracts the top domains for a subset of the hmmerFile specified in the subSetFile\n";
		help+="\t<input> = <hmmerFile> <subSetFile>\n";
		help+="antiSubTop - extracts the top domains for a subset of the hmmerFile specified as not in the subSetFile\n";
		help+="\t<input> = <hmmerFile> <subSetFile>\n";
		help+="tabulated - extracts a tabulated resultfile\n";
		help+="\t<input> = <hmmerFile>\n";
		help+="tabulatedTop - extracts the n best hmmhits in a tabulated resultfile\n";
		help+="\t<input> = <hmmerFile> <n>\n";
		help+="cluster - extracts the n (0 for all) first clusters of overlapping (Only overlapping the best hit in each cluster) domains\n";
		help+="\t<input> = <hmmerFile> <n>\n";
		
		return help;
	}

	private static void cluster(String hmmerFile,int n)throws Exception{
		if (n==0) {
			n=Integer.MAX_VALUE;
		}
		hmmerParser hp=new hmmerParser(new BufferedReader(new FileReader(hmmerFile)));
		hmmerAlignment ha;
		System.out.println("qName"+sep+"qStart"+sep+"qEnd"+sep+"model"+sep+"mStart"+sep+"mEnd"+sep+"score"+sep+"e-value"+sep+"Description"+sep+"cluster");
		for(;hp.hasMore();){
			ha=hp.nextHit();
			boolean[] used=new boolean[ha.hmms.length];
			hmmerModelAlignment[] hmas=ha.getTopDomainsByEvalue();
			int best;
			for(int i=0;i<hmas.length&&i<n;i++){
				//find best
				best=0;
				for(;best<hmas.length;best++){
					if(!used[best]){
						used[best]=true;
						break;
					}
				}
				if(best>=hmas.length){
					break;
				}
				//print the current best domain
				System.out.println(ha.qname+sep+hmas[best].tstart+sep+hmas[best].tend+sep+hmas[best].hmmname+sep+hmas[best].hmmstart+sep+hmas[best].hmmend+sep+hmas[best].score+sep+hmas[best].eValue+sep+ha.qdescription+sep+i);
				//check which other domains that overlap the current best and print them
				for(int j=best+1;j<hmas.length;j++){
					if(!used[j]){
						//check overlap
						if((hmas[j].tstart>hmas[best].tstart && hmas[j].tstart<hmas[best].tend)||(hmas[j].tend>hmas[best].tstart && hmas[j].tend<hmas[best].tend) || (hmas[j].tstart<hmas[best].tstart && hmas[j].tend>hmas[best].tend)){
							//make used and print
							used[j]=true;
							System.out.println(ha.qname+sep+hmas[best].tstart+sep+hmas[best].tend+sep+hmas[best].hmmname+sep+hmas[best].hmmstart+sep+hmas[best].hmmend+sep+hmas[best].score+sep+hmas[best].eValue+sep+ha.qdescription+sep+i);
						}
					}
				}
				
			}
		}
	}
	
	private static void tabulated(String hmmerFile) throws Exception{
		hmmerParser hp=new hmmerParser(new BufferedReader(new FileReader(hmmerFile)));
		hmmerAlignment ha;
		//print header
		System.out.println("qName"+sep+"qStart"+sep+"qEnd"+sep+"model"+sep+"mStart"+sep+"mEnd"+sep+"score"+sep+"e-value"+sep+"Description");
		for(;hp.hasMore();){
			ha=hp.nextHit();
			for (int i = 0; i < ha.hmms.length; i++) {
				hmmerModelAlignment hma = ha.hmms[i];
				System.out.println(ha.qname+sep+hma.tstart+sep+hma.tend+sep+hma.hmmname+sep+hma.hmmstart+sep+hma.hmmend+sep+hma.score+sep+hma.eValue+sep+ha.qdescription);
			}
		}
	}
	private	static void tabulatedTop(String hmmerfile,int nr)throws Exception{
		hmmerParser hp=new hmmerParser(new BufferedReader(new FileReader(hmmerfile)));
		hmmerAlignment ha;
		hmmerModelAlignment[] hma;
//		print header
		System.out.println("qName"+sep+"qStart"+sep+"qEnd"+sep+"model"+sep+"mStart"+sep+"mEnd"+sep+"score"+sep+"e-value"+sep+"Description");
		for(;hp.hasMore();){
			ha=hp.nextHit();
			hma=ha.getTopDomainsByEvalue();
			for(int i=0;i<nr&&i<hma.length;i++){
				System.out.println(ha.qname+sep+hma[i].tstart+sep+hma[i].tend+sep+hma[i].hmmname+sep+hma[i].hmmstart+sep+hma[i].hmmend+sep+hma[i].score+sep+hma[i].eValue+sep+ha.qdescription);
			}
		}
	}
	
	public static void extract_topDomains(String hmmerFile,String subSetFile,boolean inSubSet)throws Exception{
		Vector<String> subSet=new Vector<String>();
		BufferedReader in=new BufferedReader(new FileReader(subSetFile));
		for(String s=in.readLine();s!=null;s=in.readLine())
			subSet.add(s);
		extract_topDomains(hmmerFile,subSet,inSubSet);
	}
	public static void extract_topDomains(String hmmerFile,Vector subSet,boolean inSubSet)throws Exception{
		hmmerParser hp=new hmmerParser(new BufferedReader(new FileReader(hmmerFile)));
		for(;hp.hasMore();){
			hmmerAlignment ha=hp.nextHit();
			if(subSet.contains(ha.qname)==inSubSet){
				System.out.println(ha.qname);
				hmmerModelAlignment[] hma=ha.getTopDomainsByScore();
				for(int i=0;i<hma.length;i++)
					System.out.println("\t"+hma[i].hmmname);
			}
		}
	}
	/**
	 * Generates names according to the same principle as used in fastaUtils
	 * @param list - the list for which to generate names
	 * @param qname - the corresponding qname
	 * @return - names in an array numbered in the same way as list
	 */
	public static String[] getFastaNames(hmmerModelAlignment[] list,String qname){
		String[] names=new String[list.length];
		Hashtable<String, Integer> nr=new Hashtable<String, Integer>();
		for(int i=0;i<list.length;i++){
			if(nr.containsKey(list[i].hmmname))
				nr.put(list[i].hmmname,new Integer(((Integer)nr.get(list[i].hmmname)).intValue()+1));
			else
				nr.put(list[i].hmmname,new Integer(1));
			names[i]=list[i].hmmname+"|"+qname+"|"+nr.get(list[i].hmmname);
		}
		return names;
	}
}
